package org.study.sync;

import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Maps;

import java.util.*;
import java.util.concurrent.*;
import java.util.function.BiConsumer;

/**
 * https://blog.csdn.net/qq_38553514/article/details/119841313
 *
 * @author Administrator
 * @date 2021-08-27
 */
public class CompletableFutureTests2 {
    // https://www.freesion.com/article/94201077205/
    ExecutorService invokeExecutor = Executors.newFixedThreadPool(10);
    ExecutorService invokeExecutor2 = Executors.newCachedThreadPool();
    ExecutorService invokeExecutor3 = Executors.newSingleThreadExecutor();
    ExecutorService invokeExecutor4 = Executors.newScheduledThreadPool(1);

    private static final String FIELD_IS_FAVORITE = "isFavorite";
    private static final String FIELD_SCHEDULED = "scheduled";
    private static final String FIELD_ORDER_STATE = "orderState";

    public static void main(String[] args) throws Exception {
        CompletableFutureTests2 completableFutureTests2 = new CompletableFutureTests2();
        LayoutEntry layoutEntry = completableFutureTests2.testFuture();
        System.out.println(layoutEntry);
    }

    private static final Map<String, BiConsumer<Object, LayoutEntry>> consumeFutureMap = new HashMap<String, BiConsumer<Object, LayoutEntry>>() {{
        put(FIELD_IS_FAVORITE, (obj, layoutEntry) -> layoutEntry.setFavorite((Boolean) obj));
        put(FIELD_SCHEDULED, (obj, layoutEntry) -> layoutEntry.setScheduled((Boolean) obj));
        put(FIELD_ORDER_STATE, (obj, layoutEntry) -> layoutEntry.setOrderState((Integer) obj));
    }};

    public LayoutEntry testFuture() throws Exception {
        LayoutEntry layoutEntry = new LayoutEntry();
        Map<String, Future> futureMap = Maps.newHashMap();
        futureMap.put(FIELD_SCHEDULED, getScheduledFuture());
        futureMap.put(FIELD_IS_FAVORITE, getIsFavoriteFuture());
        futureMap.put(FIELD_ORDER_STATE, getOrderStateFuture());
        Thread.sleep(3000);
        setThirdFieldVal(layoutEntry, futureMap);
        return layoutEntry;
    }

    private void setThirdFieldVal(LayoutEntry layoutEntry, Map<String, Future> futureMap) {
        futureMap.forEach((fieldName, future) -> {
            try {
                Object fieldVal = future.get(300, TimeUnit.MILLISECONDS);
                Optional.ofNullable(consumeFutureMap.get(fieldName)).ifPresent(consumer -> consumer.accept(fieldVal, layoutEntry));
            } catch (Exception e) {
                System.err.println("set third field val have Exception------>" + e);
            }
        });
    }

    private Future getIsFavoriteFuture() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            String threadName = Thread.currentThread().getName() + "---isFavorite";
            System.out.println(threadName + " have execute!!!");
            return Boolean.TRUE;
        }, invokeExecutor);
        return future;
    }

    private Future getScheduledFuture() {
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
            String threadName = Thread.currentThread().getName() + "---scheduled";
            System.out.println(threadName + " have execute!!!");
            return Boolean.TRUE;
        }, invokeExecutor);
        return future;
    }

    private Future getOrderStateFuture() {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            String threadName = Thread.currentThread().getName() + "---isFavorite";
            System.out.println(threadName + " have execute!!!");
            return 100;
        }, invokeExecutor);
        return future;
    }
}

class LayoutEntry {
    private Boolean isFavorite;
    private Boolean scheduled;
    private Integer orderState;

    public Boolean getFavorite() {
        return isFavorite;
    }

    public void setFavorite(Boolean favorite) {
        isFavorite = favorite;
    }

    public Boolean getScheduled() {
        return scheduled;
    }

    public void setScheduled(Boolean scheduled) {
        this.scheduled = scheduled;
    }

    public Integer getOrderState() {
        return orderState;
    }

    public void setOrderState(Integer orderState) {
        this.orderState = orderState;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}